#! /usr/bin/env perl
##
## Copyright (C) by Argonne National Laboratory
##     See COPYRIGHT in top-level directory
##

use warnings;
use strict;

# Check to make sure the file was passed in as a parameter
if ($#ARGV != 0) {
    print "Usage: buildiface <filename>\n";
    exit 1;
}

open(FD, $ARGV[0]) || die "Could not open file " . $ARGV[0];

while (<FD>) {
    if (/\/\*\s*Begin Prototypes/) { last; }
}

my $eol = 1;
my $fullline = "";
my $tab = "    ";
my $retarg;
my $routine;
my $args;
my @arglist;
my $fname;
my $cdesc_routine;
my $x;
my $y;
my @argbits;
my $num_dtypes;
my @dtype_bind;
my $io_header;
my $make_exists = 0;

open(OUTFD, ">all_romio_symbols.c") || die "Could not open file all_romio_symbols.c";
print OUTFD <<EOT;
/*
 * Copyright (C) by Argonne National Laboratory
 *     See COPYRIGHT in top-level directory
 *
 * This file is automatically generated by buildiface
 * DO NOT EDIT
 */

/*
 * This file is created for the sole purpose of referencing all the symbols
 * in ROMIO.
 *
 * All ROMIO public symbols are being added into the libromio convenience
 * library, which is LIBADD'ed into libmpi.  The correct behavior would
 * be for libtool to add -Wl,--whole-archive to the link line, thus
 * forcing all symbols in libromio to end up in libmpi.  However, in some
 * cases, this is not working out correctly.  For example, with the
 * Absoft compiler, the linker flags were being reordered thus causing
 * the -Wl,--whole-archive flag to not correspond to libromio.
 * Consequently, only symbols that were used from within the other
 * functions of libmpi were being included.
 *
 * In the past, we got lucky in two ways:
 *
 * 1. We were including all the Fortran 77 symbols into libmpi.  Since
 * the Fortran symbols were calling the C ROMIO symbols, those ROMIO
 * symbols were pulled in even without -Wl,--whole-archive.
 *
 * 2. The problem only showed up with absoft and nag, both of which are
 * Fortran-only compilers.  If a C compiler has this issue, it should
 * have shown up when Fortran support is disabled.
 */

#include "mpiimpl.h"

#include <stdio.h>

void MPIR_All_romio_symbols(void);
void MPIR_All_romio_symbols(void)
{
#ifdef MPI_MODE_RDONLY
EOT

while (<FD>) {
    if (/\/\*\s*End Prototypes/) { last; }

    if (/\/\*\s*Begin Skip Prototypes/) {
        while (<FD>) {
            if (/\/\*\s*End Skip Prototypes/) { last; }
        }
    }

    # If we found a semi-colon at the end, that's the end of the line.
    # This is not perfect (e.g., does not work when a single line has
    # multiple semi-colon separated statements), but should be good
    # enough for the MPICH mpi.h file
    if (/.*;/) { $eol = 1; }
    else { $eol = 0; }

    chomp($_);
    $fullline .= "$_";
    if ($eol == 0) { next; }

    # We got the entire prototype in a single line

    # parse out comments
    $fullline =~ s+/\*.*\*/++g;

    # parse out attributes
    $fullline =~ s/MPICH_ATTR_POINTER_WITH_TYPE_TAG\(.*\)//g;

    # cleanup pointer format
    $fullline =~ s/\s*\*/* /g;

    # parse out unnecessary spaces
    $fullline =~ s/^\s*//g;
    $fullline =~ s/\s*$//g;
    $fullline =~ s/\s*;/;/g;
    $fullline =~ s/\s\s*/ /g;

    # split the line into the return type, routine name, and arguments
    $fullline =~ m/([^ ]*) ([^(]*)\((.*)\)/;
    $retarg = $1;
    $routine = $2;
    $args = $3;

    # cleanup args
    $args =~ s/^\s*//g;
    $args =~ s/\s*$//g;

    @arglist = split(/,/, $args);

    for ($x = 0; $x <= $#arglist; $x++) {
	$arglist[$x] =~ s/^\s*//g;
	$arglist[$x] =~ s/\s*$//g;
    }

    print OUTFD "${tab}{\n";
    for ($x = 0; $x <= $#arglist; $x++) {
	print OUTFD "${tab}${tab}$arglist[$x]";
	if ($arglist[$x] =~ /\*/) {
	    print OUTFD " = NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_Comm/) {
	    print OUTFD " = MPI_COMM_NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_Info/) {
	    print OUTFD " = MPI_INFO_NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_File/) {
	    print OUTFD " = MPI_FILE_NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_Datatype/) {
	    print OUTFD " = MPI_DATATYPE_NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_Errhandler/) {
	    print OUTFD " = MPI_ERRHANDLER_NULL;\n";
	}
	elsif ($arglist[$x] =~ /MPI_Offset|MPI_Count/) {
	    print OUTFD " = 0;\n";
	}
	elsif ($arglist[$x] =~ /int/) {
	    print OUTFD " = 0;\n";
	}
	else {
	    print "$arglist[$x]\n";
	    print OUTFD ";\n";
	}
    }
    print OUTFD "\n${tab}${tab}$routine(";
    for ($x = 0; $x <= $#arglist; $x++) {
	@argbits = split(/ /, $arglist[$x]);

	if ($x < $#arglist) {
	    print OUTFD "$argbits[$#argbits], ";
	}
	else {
	    print OUTFD "$argbits[$#argbits]);\n";
	}
    }
    print OUTFD "${tab}}\n\n";

    $fullline = "";
}

# A few symbols are not in mpio.h
print OUTFD <<EOT;
    {
        MPI_Fint fh = 0;

        MPI_File_f2c(fh);
    }

    {
        MPI_File fh = MPI_FILE_NULL;

        MPI_File_c2f(fh);
    }

    MPIR_Comm_split_filesystem(MPI_COMM_NULL, 0, NULL, NULL);
#endif /* MPI_MODE_RDONLY */
}
EOT

close FD;
close OUTFD;
